// $Id: jatte.c 10 2013-09-13 05:40:46Z alan.watson.f@gmail.com $

// Copyright 2013 Alan M. Watson

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "jatte.h"

////////////////////////////////////////////////////////////////////////////////

void
jatte_error(const char *format, ...)
{
  fprintf(stderr, "error: ");
  va_list ap;
  va_start(ap, format);
  vfprintf(stderr, format, ap);
  va_end(ap);
  fprintf(stderr, "\n");
  exit(1);
}

////////////////////////////////////////////////////////////////////////////////

char *
jatte_vmprintf(const char *format, va_list ap)
{
  va_list aq;
  va_copy(aq, ap);
  int n = vsnprintf(NULL, 0, format, ap);
  char *s = jatte_checked_malloc(n + 1);
  vsprintf(s, format, aq);
  return s;  
}

char *
jatte_mprintf(const char *format, ...)
{
  va_list ap;
  va_start(ap, format);
  char *s = jatte_vmprintf(format, ap);
  va_end(ap);
  return s;  
}

////////////////////////////////////////////////////////////////////////////////

void *
jatte_checked_malloc(size_t n)
{
  void *p = malloc(n);
  if (p == NULL) {
    jatte_error("malloc failed.");
  }
  return p;
}

FILE *
jatte_checked_fopen(const char *name, const char *mode)
{
  FILE *fp = fopen(name, mode);
  if (fp == NULL) {
    jatte_error("unable to open \"%s\".", name);
  }
  return fp;    
}

////////////////////////////////////////////////////////////////////////////////

unsigned int **
jatte_checked_alloc_2d_unsigned_int_array(size_t ny, size_t nx)
{
  unsigned int **z = jatte_checked_malloc(ny * sizeof(*z));
  for (size_t iy = 0; iy < ny; ++iy) {
    z[iy] = jatte_checked_malloc(nx * sizeof(*z));
  }
  return z;
}

void
jatte_free_2d_unsigned_int_array(size_t ny, size_t nx, unsigned int **z)
{
  for (size_t iy = 0; iy < ny; ++iy) {
    free(z[iy]);
  }
  free(z);
}

////////////////////////////////////////////////////////////////////////////////

static void
wfits_write_boolean(FILE *fp, const char *name, int value)
{
  char s[81];
  sprintf(s, "%20.20s", value ? "T" : "F");
  fprintf(fp, "%-8.8s= %-70.70s", name, s);
}

static void
wfits_write_size_t(FILE *fp, const char *name, size_t value)
{
  char s[81];
  sprintf(s, "%20zd", value);
  fprintf(fp, "%-8.8s= %-70.70s", name, s);
}

static void
wfits_write_end(FILE *fp)
{
  fprintf(fp, "%-80.80s", "END");
}

static void
wfits_pad(FILE *fp, int c)
{
  size_t n = ftell(fp);
  while (n % 2880 != 0) {
    putc(c, fp);
    ++n;
  }
}

void
jatte_write_fits_2d_unsigned_int(FILE *fp, size_t ny, size_t nx, unsigned int **z)
{
  wfits_write_boolean(fp, "SIMPLE", 1);
  wfits_write_size_t(fp, "BITPIX", 16);
  wfits_write_size_t(fp, "NAXIS" , 2);
  wfits_write_size_t(fp, "NAXIS1", nx);
  wfits_write_size_t(fp, "NAXIS2", ny);
  wfits_write_size_t(fp, "BSCALE", 1);
  wfits_write_size_t(fp, "BZERO", 0x8000);
  wfits_write_end(fp);
  wfits_pad(fp, ' ');
  for (size_t iy = 0; iy < ny; ++iy) {
    for (size_t ix = 0; ix < nx; ++ix) {
      unsigned int u = z[iy][ix];
      u -= 0x8000;
      unsigned int b0 = u % 0x100u;
      unsigned int b1 = u / 0x100u;
      putc(b1, fp);
      putc(b0, fp);
    }
  }
  wfits_pad(fp, 0);
}
